// internal/libvirt/xmlbuilder/xml_builder.go
package xmlbuilder

import (
	"fmt"
	"strings"

	"github.com/google/uuid"
	"libvirt.org/go/libvirtxml"

	"virt-manager-go/internal/domain"
)

type xmlBuilder struct{}

func NewXMLBuilder() domain.XMLBuilder {
	return &xmlBuilder{}
}

// BuildVMXML 构建完整的虚拟机 XML
func (b *xmlBuilder) BuildVMXML(config *domain.VMCreateConfig) (string, error) {
	// 设置默认值
	if config.Architecture == "" {
		config.Architecture = "x86_64"
	}
	if config.OSType == "" {
		config.OSType = "hvm"
	}

	// 构建基础域配置
	domainConfig := &libvirtxml.Domain{
		Type: "kvm",
		Name: config.Name,
		UUID: uuid.New().String(),
		Memory: &libvirtxml.DomainMemory{
			Value: uint(config.Memory * 1024), // MB to KB
			Unit:  "KiB",
		},
		CurrentMemory: &libvirtxml.DomainCurrentMemory{
			Value: uint(config.Memory * 1024),
			Unit:  "KiB",
		},
		VCPU: &libvirtxml.DomainVCPU{
			Value: config.CPUs,
		},
		OS: &libvirtxml.DomainOS{
			Type: &libvirtxml.DomainOSType{
				Arch:    config.Architecture,
				Machine: "pc-q35-7.2", // 现代机器类型
				Type:    config.OSType,
			},
		},
		Features: &libvirtxml.DomainFeatureList{
			ACPI: &libvirtxml.DomainFeature{},
			APIC: &libvirtxml.DomainFeatureAPIC{},
		},
		CPU: &libvirtxml.DomainCPU{
			Mode: "host-passthrough", // 最佳性能
		},
		OnPoweroff: "destroy",
		OnReboot:   "restart",
		OnCrash:    "restart",
		Devices: &libvirtxml.DomainDeviceList{
			Emulator: "/usr/bin/qemu-system-" + config.Architecture,
		},
	}

	// 配置启动顺序
	bootOrder := []string{}

	// 根据安装方式配置启动设备和磁盘
	if config.InstallISO != "" {
		// ISO 安装：添加 CDROM 并设置为第一启动项
		if err := b.addCDROM(domainConfig, config.InstallISO, 1); err != nil {
			return "", err
		}
		bootOrder = append(bootOrder, "cdrom")

		// 添加主磁盘（如果配置中有）
		if len(config.Disks) > 0 {
			for i, diskCfg := range config.Disks {
				if err := b.addDisk(domainConfig, diskCfg, i+2); err != nil {
					return "", err
				}
			}
			bootOrder = append(bootOrder, "hd")
		}
	} else if config.InstallPXE {
		// PXE 安装：配置网络启动
		bootOrder = append(bootOrder, "network")

		// 添加磁盘
		for i, diskCfg := range config.Disks {
			if err := b.addDisk(domainConfig, diskCfg, i+1); err != nil {
				return "", err
			}
		}
		bootOrder = append(bootOrder, "hd")
	} else if config.ImportDisk != "" {
		// 导入磁盘：使用现有磁盘
		importDisk := &domain.DiskConfig{
			Type:   "file",
			Device: "disk",
			Source: config.ImportDisk,
			Format: "qcow2", // 默认格式
			Bus:    "virtio",
			Target: "vda",
		}
		if err := b.addDisk(domainConfig, importDisk, 1); err != nil {
			return "", err
		}
		bootOrder = append(bootOrder, "hd")
	} else {
		// 仅磁盘
		for i, diskCfg := range config.Disks {
			if err := b.addDisk(domainConfig, diskCfg, i+1); err != nil {
				return "", err
			}
		}
		bootOrder = append(bootOrder, "hd")
	}

	// 设置启动顺序
	domainConfig.OS.BootDevices = make([]libvirtxml.DomainBootDevice, len(bootOrder))
	for i, dev := range bootOrder {
		domainConfig.OS.BootDevices[i] = libvirtxml.DomainBootDevice{Dev: dev}
	}

	// // 添加网络接口
	// if len(config.Networks) == 0 {
	// 	// 默认网络
	// 	config.Networks = []*domain.NetworkConfig{
	// 		{
	// 			Type:   "network",
	// 			Source: "default",
	// 			Model:  "virtio",
	// 		},
	// 	}
	// }
	// for _, netCfg := range config.Networks {
	// 	if err := b.addNetwork(domainConfig, netCfg); err != nil {
	// 		return "", err
	// 	}
	// }

	// 添加图形设备
	if config.Graphics != nil {
		b.addGraphics(domainConfig, config.Graphics)
	} else {
		// 默认 VNC
		b.addGraphics(domainConfig, &domain.GraphicsConfig{
			Type:   "vnc",
			Listen: "0.0.0.0",
			Port:   -1, // 自动分配
		})
	}

	// 添加串行控制台和视频设备
	b.addConsole(domainConfig)
	b.addVideo(domainConfig)
	b.addInput(domainConfig)

	// 序列化为 XML
	xml, err := domainConfig.Marshal()
	if err != nil {
		return "", fmt.Errorf("failed to marshal domain XML: %w", err)
	}

	return xml, nil
}

// addDisk 添加磁盘设备
func (b *xmlBuilder) addDisk(domainConfig *libvirtxml.Domain, diskCfg *domain.DiskConfig, bootOrder int) error {
	if diskCfg.Bus == "" {
		diskCfg.Bus = "virtio"
	}
	if diskCfg.Format == "" {
		diskCfg.Format = "qcow2"
	}
	if diskCfg.Target == "" {
		diskCfg.Target = b.generateDiskTarget(diskCfg.Bus, bootOrder-1)
	}

	disk := libvirtxml.DomainDisk{
		Device: diskCfg.Device,
		Driver: &libvirtxml.DomainDiskDriver{
			Name: "qemu",
			Type: diskCfg.Format,
		},
		Target: &libvirtxml.DomainDiskTarget{
			Dev: diskCfg.Target,
			Bus: diskCfg.Bus,
		},
	}

	// 设置源
	if diskCfg.Type == "file" || diskCfg.Type == "" {
		disk.Source = &libvirtxml.DomainDiskSource{
			File: &libvirtxml.DomainDiskSourceFile{
				File: diskCfg.Source,
			},
		}
	} else if diskCfg.Type == "block" {
		disk.Source = &libvirtxml.DomainDiskSource{
			Block: &libvirtxml.DomainDiskSourceBlock{
				Dev: diskCfg.Source,
			},
		}
	}

	// 设置缓存模式
	if diskCfg.Cache != "" {
		disk.Driver.Cache = diskCfg.Cache
	}

	// 设置启动顺序
	if diskCfg.Bootable {
		disk.Boot = &libvirtxml.DomainDeviceBoot{Order: uint(bootOrder)}
	}

	domainConfig.Devices.Disks = append(domainConfig.Devices.Disks, disk)
	return nil
}

// addCDROM 添加 CDROM 设备
func (b *xmlBuilder) addCDROM(domainConfig *libvirtxml.Domain, isoPath string, bootOrder int) error {
	cdrom := libvirtxml.DomainDisk{
		Device: "cdrom",
		Driver: &libvirtxml.DomainDiskDriver{
			Name: "qemu",
			Type: "raw",
		},
		Source: &libvirtxml.DomainDiskSource{
			File: &libvirtxml.DomainDiskSourceFile{
				File: isoPath,
			},
		},
		Target: &libvirtxml.DomainDiskTarget{
			Dev: "sda",
			Bus: "sata",
		},
		ReadOnly: &libvirtxml.DomainDiskReadOnly{},
		Boot:     &libvirtxml.DomainDeviceBoot{Order: uint(bootOrder)},
	}

	domainConfig.Devices.Disks = append(domainConfig.Devices.Disks, cdrom)
	return nil
}

// addNetwork 添加网络接口
// func (b *xmlBuilder) addNetwork(domainConfig *libvirtxml.Domain, netCfg *domain.NetworkConfig) error {
// 	if netCfg.Model == "" {
// 		netCfg.Model = "virtio"
// 	}

// 	iface := libvirtxml.DomainInterface{
// 		Model: &libvirtxml.DomainInterfaceModel{
// 			Type: netCfg.Model,
// 		},
// 	}

// 	// 设置 MAC 地址
// 	if netCfg.MAC != "" {
// 		iface.MAC = &libvirtxml.DomainInterfaceMAC{Address: netCfg.MAC}
// 	}

// 	// 设置网络源
// 	if netCfg.Type == "network" {
// 		iface.Source = &libvirtxml.DomainInterfaceSource{
// 			Network: &libvirtxml.DomainInterfaceSourceNetwork{
// 				Network: netCfg.Source,
// 			},
// 		}
// 	} else if netCfg.Type == "bridge" {
// 		iface.Source = &libvirtxml.DomainInterfaceSource{
// 			Bridge: &libvirtxml.DomainInterfaceSourceBridge{
// 				Bridge: netCfg.Source,
// 			},
// 		}
// 	}

// 	domainConfig.Devices.Interfaces = append(domainConfig.Devices.Interfaces, iface)
// 	return nil
// }

// addGraphics 添加图形设备
func (b *xmlBuilder) addGraphics(domainConfig *libvirtxml.Domain, gfxCfg *domain.GraphicsConfig) {
	if gfxCfg.Type == "vnc" {
		vnc := libvirtxml.DomainGraphic{
			VNC: &libvirtxml.DomainGraphicVNC{
				Port:     gfxCfg.Port,
				AutoPort: "yes",
			},
		}
		if gfxCfg.Listen != "" {
			vnc.VNC.Listeners = []libvirtxml.DomainGraphicListener{
				{Address: &libvirtxml.DomainGraphicListenerAddress{Address: gfxCfg.Listen}},
			}
		}
		if gfxCfg.Password != "" {
			vnc.VNC.Passwd = gfxCfg.Password
		}
		domainConfig.Devices.Graphics = append(domainConfig.Devices.Graphics, vnc)
	} else if gfxCfg.Type == "spice" {
		spice := libvirtxml.DomainGraphic{
			Spice: &libvirtxml.DomainGraphicSpice{
				Port:     gfxCfg.Port,
				AutoPort: "yes",
			},
		}
		if gfxCfg.Listen != "" {
			spice.Spice.Listeners = []libvirtxml.DomainGraphicListener{
				{Address: &libvirtxml.DomainGraphicListenerAddress{Address: gfxCfg.Listen}},
			}
		}
		domainConfig.Devices.Graphics = append(domainConfig.Devices.Graphics, spice)
	}
}

// addConsole 添加串行控制台
func (b *xmlBuilder) addConsole(domainConfig *libvirtxml.Domain) {
	port := uint(0)
	console := libvirtxml.DomainConsole{
		Target: &libvirtxml.DomainConsoleTarget{
			Type: "serial",
			Port: &port,
		},
	}

	domainConfig.Devices.Consoles = append(domainConfig.Devices.Consoles, console)
}

// addVideo 添加视频设备
func (b *xmlBuilder) addVideo(domainConfig *libvirtxml.Domain) {
	video := libvirtxml.DomainVideo{
		Model: libvirtxml.DomainVideoModel{
			Type: "qxl",
			Ram:  uint(65536),
			VRam: uint(65536),
		},
	}

	domainConfig.Devices.Videos = append(domainConfig.Devices.Videos, video)
}

// addInput 添加输入设备
func (b *xmlBuilder) addInput(domainConfig *libvirtxml.Domain) {
	// 添加鼠标
	mouse := libvirtxml.DomainInput{
		Type: "mouse",
		Bus:  "ps2",
	}
	// 添加键盘
	keyboard := libvirtxml.DomainInput{
		Type: "keyboard",
		Bus:  "ps2",
	}

	domainConfig.Devices.Inputs = append(domainConfig.Devices.Inputs, mouse, keyboard)
}

// generateDiskTarget 生成磁盘目标名称
func (b *xmlBuilder) generateDiskTarget(bus string, index int) string {
	var prefix string
	switch bus {
	case "virtio":
		prefix = "vd"
	case "scsi":
		prefix = "sd"
	case "sata":
		prefix = "sd"
	case "ide":
		prefix = "hd"
	default:
		prefix = "vd"
	}

	// 生成 vda, vdb, vdc...
	letter := rune('a' + index)
	return fmt.Sprintf("%s%c", prefix, letter)
}

// BuildDiskXML 构建单个磁盘 XML
func (b *xmlBuilder) BuildDiskXML(disk *domain.DiskConfig) (string, error) {
	domainConfig := &libvirtxml.Domain{
		Devices: &libvirtxml.DomainDeviceList{},
	}

	if err := b.addDisk(domainConfig, disk, 1); err != nil {
		return "", err
	}

	xml, err := domainConfig.Marshal()
	if err != nil {
		return "", err
	}

	return xml, nil
}

// BuildNetworkXML 构建单个网络接口 XML
// func (b *xmlBuilder) BuildNetworkXML(net *domain.NetworkConfig) (string, error) {
// 	domainConfig := &libvirtxml.Domain{
// 		Devices: &libvirtxml.DomainDeviceList{},
// 	}

// 	if err := b.addNetwork(domainConfig, net); err != nil {
// 		return "", err
// 	}

// 	xml, err := domainConfig.Marshal()
// 	if err != nil {
// 		return "", err
// 	}

// 	return xml, nil
// }

// ParseVMXML 解析虚拟机 XML
func (b *xmlBuilder) ParseVMXML(xmlData string) (*domain.VMCreateConfig, error) {
	var domainConfig libvirtxml.Domain
	if err := domainConfig.Unmarshal(xmlData); err != nil {
		return nil, err
	}

	config := &domain.VMCreateConfig{
		Metadata: make(map[string]string),
	}

	if domainConfig.VCPU != nil {
		config.CPUs = uint(domainConfig.VCPU.Value)
	}

	if domainConfig.Memory != nil {
		mem := uint64(domainConfig.Memory.Value / 1024) // KB to MB
		config.Memory = mem
	}

	if domainConfig.OS != nil && domainConfig.OS.Type != nil {
		config.OSType = domainConfig.OS.Type.Type
		config.Architecture = domainConfig.OS.Type.Arch
	}

	// 解析磁盘
	config.Disks = make([]*domain.DiskConfig, 0)
	for _, disk := range domainConfig.Devices.Disks {
		diskCfg := &domain.DiskConfig{
			Device: disk.Device,
		}

		if disk.Driver != nil {
			diskCfg.Format = disk.Driver.Type
		}

		if disk.Target != nil {
			diskCfg.Target = disk.Target.Dev
			diskCfg.Bus = disk.Target.Bus
		}

		if disk.Source != nil {
			if disk.Source.File != nil {
				diskCfg.Type = "file"
				diskCfg.Source = disk.Source.File.File
			} else if disk.Source.Block != nil {
				diskCfg.Type = "block"
				diskCfg.Source = disk.Source.Block.Dev
			}
		}

		config.Disks = append(config.Disks, diskCfg)
	}

	// 解析网络
	config.Networks = make([]*domain.NetworkInterfaceConfig, 0)
	for _, iface := range domainConfig.Devices.Interfaces {
		netCfg := &domain.NetworkInterfaceConfig{}

		if iface.Model != nil {
			netCfg.Model = iface.Model.Type
		}

		if iface.MAC != nil {
			netCfg.MAC = iface.MAC.Address
		}

		if iface.Source != nil {
			if iface.Source.Network != nil {
				netCfg.Type = "network"
				netCfg.Source = iface.Source.Network.Network
			} else if iface.Source.Bridge != nil {
				netCfg.Type = "bridge"
				netCfg.Source = iface.Source.Bridge.Bridge
			}
		}

		config.Networks = append(config.Networks, netCfg)
	}

	return config, nil
}

// CloneVMXML 克隆虚拟机 XML（修改名称、UUID、MAC 等）
func (b *xmlBuilder) CloneVMXML(srcXML, newName string) (string, error) {
	domainConfig := &libvirtxml.Domain{}
	if err := domainConfig.Unmarshal(srcXML); err != nil {
		return "", fmt.Errorf("failed to unmarshal source XML: %w", err)
	}

	// 修改名称
	domainConfig.Name = newName

	// 生成新的 UUID
	domainConfig.UUID = uuid.New().String()

	// 修改所有网络接口的 MAC 地址
	for i := range domainConfig.Devices.Interfaces {
		domainConfig.Devices.Interfaces[i].MAC = nil // 让 libvirt 自动生成
	}

	// 修改磁盘路径
	for i := range domainConfig.Devices.Disks {
		disk := &domainConfig.Devices.Disks[i]
		if disk.Source != nil && disk.Source.File != nil {
			oldPath := disk.Source.File.File
			// 替换文件名中的旧 VM 名称
			newPath := strings.Replace(oldPath, domainConfig.Name, newName, 1)
			disk.Source.File.File = newPath
		}
	}

	xml, err := domainConfig.Marshal()
	if err != nil {
		return "", fmt.Errorf("failed to marshal cloned XML: %w", err)
	}

	return xml, nil
}
